package com.csoft.riskroll;

import java.util.Arrays;

/**
 * RiskRoll v 1.0
 * @author John Cline
 * 28 March 2010
 *
 * This class represents a handful of risk die. Contains both sides,
 * attack and defense. Functions supported include rolling the die, 
 * determining which side won/lost (and how much), and setting the number of 
 * die to roll each time.
 * 
 * Dice icon obtained from http://www.psdgraphics.com/
 * This code is distributed under Apache v2, available http://www.apache.org/licenses/LICENSE-2.0
 */

public class RiskDie {

    protected int attackDieCount;
    protected int defendDieCount;
    protected int aLosses;
    protected int dLosses;
    protected int[] attackDie;
    protected int[] defendDie;
    protected boolean diceRolled;
    protected boolean nukeBlast;
    
    protected static final int MAX_ATTACK_DIE = 3;
    protected static final int MAX_DEFEND_DIE = 2;
    
    public RiskDie(int numAttack, int numDefend) {
    	/*
    	 * Constructor. Initializes array to whatever max sizes are,
    	 * sets losses to 0, puts the number of attack and defend die
    	 * at the passed value, and sets dice rolled to false;
    	 */
    	attackDie = new int[MAX_ATTACK_DIE];
    	defendDie = new int[MAX_DEFEND_DIE];
    	if (numAttack <= 0 || numAttack > MAX_ATTACK_DIE) {
    		attackDieCount = 1;
    	} else {
    		attackDieCount = numAttack;
    	}
    	if (numDefend <= 0 || numDefend > MAX_DEFEND_DIE) {
    		defendDieCount = 1;
    	} else {
    		defendDieCount = numDefend;
    	}
        resetDie();
    }
    
    public void setNumDie(int numAttack, int numDefend) {
    	/*
    	 * Sets the number of die to roll based on passed values as long as it is in a valid
    	 * range. Otherwise it does nothing.
    	 */
    	if (numAttack > 0 && numAttack <= MAX_ATTACK_DIE) {
    		attackDieCount = numAttack;
    	}
    	if (numDefend > 0 && numDefend <= MAX_DEFEND_DIE) {
    		defendDieCount = numDefend;
    	}
    }
    
    public int[] rollDie() {
    	/*
    	 * Rolls the die, corresponding to the number set upon construction
    	 * First checks to see if more defense die are rolled than attack,
    	 * which is not allowed by Risk rules. Returns an array of [-1,-1] if 
    	 * this was the case.
    	 * Otherwise, rolls each die selected and sorts highest to lowest for display.
    	 * Returns getResults()
    	 */
    	resetDie();
    	if ((defendDieCount > attackDieCount)
    		|| (attackDieCount == 0) || (defendDieCount == 0)) {
    		int[] results = new int[2];
    		results[0] = -1; results[1] = -1;
    		return results;
    	} else {
    		for (int i=0;i<attackDieCount;i++) {
    			attackDie[i] = roll();
    		}
    		for (int i=0;i<defendDieCount;i++) {
    			defendDie[i] = roll();
    		}
    		Arrays.sort(attackDie);
    		for( int i = 0; i < attackDie.length/2; ++i ) {
    			int temp = attackDie[i];
    			attackDie[i] = attackDie[attackDie.length - i - 1];
    			attackDie[attackDie.length - i - 1] = temp;
    		} 
    		Arrays.sort(defendDie);
    		for( int i = 0; i < defendDie.length/2; ++i ) {
    			int temp = defendDie[i];
    			defendDie[i] = defendDie[defendDie.length - i - 1];
    			defendDie[defendDie.length - i - 1] = temp;
    		} 
    		diceRolled = true;
    		calcLosses();
    	}
    	if ((attackDie[0] == attackDie[1]) && (attackDie[1] == attackDie[2])) {
    		nukeBlast = true;
    	} else nukeBlast = false;
    	return getResults();
    }
    
    protected int roll() {
    	/*
    	 * Rolls a die, returns an int with the roll.
    	 */
    	return (int) ((Math.random()*6) + 1);
    }
    
    protected boolean isWinner(int attack, int defend) {
    	/*
    	 * Returns whether or not attack won the roll.
    	 */
    	if (attack > defend) return true;
    	else return false;
    }
    
    public void resetDie() {
    	/*
    	 * Resets die to 0 and losses for both sides to 0.
    	 */
    	aLosses = 0;
    	dLosses = 0;
    	for (int i=0;i<attackDie.length;i++) {
    		attackDie[i] = 0;
    	}
    	for (int i=0;i<defendDie.length;i++) {
    		defendDie[i] = 0;
    	}
    	diceRolled = false;
    }
    
    public int[] getResults() {
    	/*
    	 * Returns an array of size two, first element containing losses for
    	 * attack and second element containing defense losses.
    	 */
    	int[] results = new int[2];
    	results[0] = aLosses;
    	results[1] = dLosses;
    	return results;
    }
    
    protected boolean calcLosses() {
    	/*
    	 * Goes through the die to determine a winner. Returns false
    	 * if die have not been rolled, otherwise returns true on completion.
    	 */
    	if (!diceRolled) return false;
    	for (int i=0;i<defendDieCount;i++) {
    		if (isWinner(attackDie[i], defendDie[i])) {
    			dLosses++;
    		} else {
    			aLosses++;
    		}
    	}
    	return true;
    }
    
    // Returns an array containing the attack die
    public int[] getAttackDie() {
    	return attackDie;
    }
    
    // Returns an array containing the defense die
    public int[] getDefendDie() {
    	return defendDie;
    }
    
    // Returns the current value of attack losses
    public int getALosses() {
    	return aLosses;
    }
    
    // Returns the current value of defense losses
    public int getDLosses() {
    	return dLosses;
    }
    
    // Returns the current value of attack die count
    public int getAttackCount() {
    	return attackDieCount;
    }
    
    // Returns the current value of defend die count
    public int getDefendCount() {
    	return defendDieCount;
    }
    
    // Returns the value of nukeBlast
    public boolean getNuke() {
    	return nukeBlast;
    }
}
